#packages
library(dplyr)
library(markovchain)
Load data
# Restore the object
Diet_Data_Clean = readRDS(file = "~/Dropbox (Edison_Lab@UGA)/Projects/vet/Deanna/Golden_Data/CleanDietData.rds")
Frequency at which participants switch categorization
data <- Diet_Data_Clean[order(Diet_Data_Clean$id, Diet_Data_Clean$calendaryear),]
# Create a list of all unique categories
all_categories <- unique(data$process.category)
# Creating sequences
data_sequence <- data %>%
group_by(id) %>%
summarise(Category_Sequence = list(process.category)) %>%
ungroup()
# Function to fit Markov chain and return a complete transition matrix
get_complete_matrix <- function(sequence) {
# Fit the Markov chain
mcFit <- markovchainFit(data = sequence)$estimate
# Create a complete matrix including all categories
complete_matrix <- matrix(0, length(all_categories), length(all_categories),
dimnames = list(all_categories, all_categories))
transitions <- mcFit@transitionMatrix
# Fill the complete matrix with existing transitions
rownames_to_use <- intersect(rownames(transitions), all_categories)
colnames_to_use <- intersect(colnames(transitions), all_categories)
complete_matrix[rownames_to_use, colnames_to_use] <- transitions[rownames_to_use, colnames_to_use]
return(complete_matrix)
}
# Adjust the function to convert sequences to transition matrix
get_transition_matrix <- function(sequence_list) {
mcList <- lapply(sequence_list, get_complete_matrix)
# Summing all matrices
matrix_sum <- Reduce("+", mcList)
return(matrix_sum / length(mcList)) # Normalizing
}
# Creating the transition matrix
transition_matrix <- get_transition_matrix(data_sequence$Category_Sequence)
print(transition_matrix)
Ultra Processed Minimally Processed Processed N/A UNK TBD
Ultra Processed 0.8549116920 0.0192556786 0.0167433202 0.0065159408 0.0010621989 0
Minimally Processed 0.0363087416 0.0519374570 0.0065820349 0.0003942181 0.0003754458 0
Processed 0.0372262374 0.0099211564 0.0181176084 0.0004380201 0.0009855453 0
N/A 0.0003285151 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0
UNK 0.0026281209 0.0006570302 0.0009855453 0.0000000000 0.0003285151 0
TBD 0.0003285151 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0

implies a significant tendency for subjects to remain in the last
category listed. This can indicate that once subjects enter this
category, they are likely to stay there, suggesting stability or a
terminal stage depending on the context of the study.
#
data$Year <- as.integer(data$calendaryear)
# Calculate the duration of stay in each category for each subject
durations <- data %>%
group_by(id, process.category) %>%
summarise(
Start_Year = min(Year),
End_Year = max(Year),
Duration = End_Year - Start_Year + 1 # +1 because if start and end year are the same, duration is 1 year
) %>%
ungroup()
`summarise()` has grouped output by 'id'. You can override using the `.groups` argument.
# View the first few rows of the durations data frame
head(durations)
# Calculate the average duration of stay per category
average_durations <- durations %>%
group_by(process.category) %>%
summarise(Average_Duration = mean(Duration))
# View the average durations
head(average_durations)
durations_datatable = datatable(durations, options = list(), class = "display")
durations_datatable
average_durations_datatable = datatable(average_durations, options = list(), class = "display")
average_durations_datatable
# Adding a small constant to handle zeros
k = 0.001
transition_df$Freq_Adjusted = transition_df$Freq + k
# Applying a log transformation (base 10)
transition_df$Log_Frequency = log10(transition_df$Freq_Adjusted)
# Converting matrix to data frame for plotting
#transition_df <- as.data.frame(as.table(transition_matrix))
# Create interactive heatmap
heatmap2 = plot_ly(data = transition_df, x = ~From, y = ~To, z = ~Log_Frequency, type = "heatmap", colors = colorRamp(c("blue", "white", "red")),
text = ~paste("Transition from", From, "to", To, "<br>Probability:", Frequency),
hoverinfo = "text") %>%
layout(title = "Transition Matrix Heatmap",
xaxis = list(title = "From Category"),
yaxis = list(title = "To Category", autorange = "reversed")) # Reversing y-axis to match heatmap conventions
heatmap2
Frequency for switching diet companies
# Create a list of all unique categories
all_categories <- unique(data$Parent_Company)
# Function to fit Markov chain and return a complete transition matrix
get_complete_matrix <- function(sequence) {
# Fit the Markov chain
mcFit <- markovchainFit(data = sequence)$estimate
# Create a complete matrix including all categories
complete_matrix <- matrix(0, length(all_categories), length(all_categories),
dimnames = list(all_categories, all_categories))
transitions <- mcFit@transitionMatrix
# Fill the complete matrix with existing transitions
rownames_to_use <- intersect(rownames(transitions), all_categories)
colnames_to_use <- intersect(colnames(transitions), all_categories)
complete_matrix[rownames_to_use, colnames_to_use] <- transitions[rownames_to_use, colnames_to_use]
return(complete_matrix)
}
# Adjust the function to convert sequences to transition matrix
get_transition_matrix <- function(sequence_list) {
mcList <- lapply(sequence_list, get_complete_matrix)
# Summing all matrices
matrix_sum <- Reduce("+", mcList)
return(matrix_sum / length(mcList)) # Normalizing
}
# Creating the transition matrix
transition_matrix <- get_transition_matrix(data_sequence$Category_Sequence)
#
data$Year <- as.integer(data$calendaryear)
# Calculate the duration of stay in each category for each subject
durations <- data %>%
group_by(id, Parent_Company) %>%
summarise(
Start_Year = min(Year),
End_Year = max(Year),
Duration = End_Year - Start_Year + 1 # +1 because if start and end year are the same, duration is 1 year
) %>%
ungroup()
`summarise()` has grouped output by 'id'. You can override using the `.groups` argument.
# View the first few rows of the durations data frame
head(durations)
# Calculate the average duration of stay per category
average_durations <- durations %>%
group_by(Parent_Company) %>%
summarise(Average_Duration = mean(Duration))
# View the average durations
head(average_durations)
durations_datatable2 = datatable(durations, options = list(), class = "display")
durations_datatable
average_durations_datatable2 = datatable(average_durations, options = list(), class = "display")
average_durations_datatable
Frequency for switching diet brands
# Create a list of all unique categories
all_categories <- unique(data$Brand_Company)
# Function to fit Markov chain and return a complete transition matrix
get_complete_matrix <- function(sequence) {
# Fit the Markov chain
mcFit <- markovchainFit(data = sequence)$estimate
# Create a complete matrix including all categories
complete_matrix <- matrix(0, length(all_categories), length(all_categories),
dimnames = list(all_categories, all_categories))
transitions <- mcFit@transitionMatrix
# Fill the complete matrix with existing transitions
rownames_to_use <- intersect(rownames(transitions), all_categories)
colnames_to_use <- intersect(colnames(transitions), all_categories)
complete_matrix[rownames_to_use, colnames_to_use] <- transitions[rownames_to_use, colnames_to_use]
return(complete_matrix)
}
# Adjust the function to convert sequences to transition matrix
get_transition_matrix <- function(sequence_list) {
mcList <- lapply(sequence_list, get_complete_matrix)
# Summing all matrices
matrix_sum <- Reduce("+", mcList)
return(matrix_sum / length(mcList)) # Normalizing
}
# Creating the transition matrix
transition_matrix <- get_transition_matrix(data_sequence$Category_Sequence)
#
data$Year <- as.integer(data$calendaryear)
# Calculate the duration of stay in each category for each subject
durations <- data %>%
group_by(id, Brand_Company) %>%
summarise(
Start_Year = min(Year),
End_Year = max(Year),
Duration = End_Year - Start_Year + 1 # +1 because if start and end year are the same, duration is 1 year
) %>%
ungroup()
`summarise()` has grouped output by 'id'. You can override using the `.groups` argument.
# View the first few rows of the durations data frame
head(durations)
# Calculate the average duration of stay per category
average_durations <- durations %>%
group_by(Brand_Company) %>%
summarise(Average_Duration = mean(Duration))
# View the average durations
head(average_durations)
durations_datatable3 = datatable(durations, options = list(), class = "display")
durations_datatable3
average_durations_datatable3 = datatable(average_durations, options = list(), class = "display")
average_durations_datatable3
save(heatmap2, file = "~/Dropbox (Edison_Lab@UGA)/Projects/vet/Deanna/Golden_Data/figures_trends.RData")
save(average_durations_datatable,durations_datatable,durations_datatable2,average_durations_datatable2,average_durations_datatable3,durations_datatable3, file = "~/Dropbox (Edison_Lab@UGA)/Projects/vet/Deanna/Golden_Data/tables_trends.RData")
Death data and diet data
# Merge the datasets
combined_data <- left_join(Death_Data_Clean, Diet_Data_Clean, by = c("id"))
Warning: Detected an unexpected many-to-many relationship between `x` and `y`.
# Calculate frequencies
condition_frequency <- combined_data %>%
group_by(process.category, condition)%>%
filter(!is.na(process.category)) %>%
summarize(frequency = n(), .groups = 'drop')
condition_frequency
# Plot the frequency of diseases by process category
disease_plot <-ggplot(condition_frequency, aes(x = condition, y = frequency, fill = process.category)) +
geom_bar(stat = "identity", position = "stack") + # 'stack' stacks the bars for different conditions
labs(title = "Frequency of Diseases by Process Category",
x = "Process Category",
y = "Frequency of Disease",
fill = "Condition") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotate x-axis labels for readability
# same but without duplicates
combined_no_dups <- combined_data %>%
filter(!is.na(process.category)) %>% # Ensure process.category is not NA
distinct(id, diagnosis_date, .keep_all = TRUE) # Remove duplicates based on id and diagnosis_date
# Calculate frequencies
condition_frequency <- combined_no_dups %>%
group_by(process.category, condition) %>%
summarize(frequency = n(), .groups = 'drop') # Calculate frequency and drop the grouping
# Plot the frequency of diseases by process category
disease_plot <- ggplot(condition_frequency, aes(x = condition, y = frequency, fill = process.category)) +
geom_bar(stat = "identity", position = "stack") + # 'stack' stacks the bars for different conditions
labs(title = "Frequency of Diseases by Process Category",
x = "Condition",
y = "Frequency of Disease",
fill = "Process Category") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotate x-axis labels for readability
print(disease_plot)

# Convert ggplot to interactive plotly chart
interactive_disease_plot <- ggplotly(disease_plot)
# Print the interactive plot
interactive_disease_plot
# Plot the frequency of diseases by process category
logdisease_plot <- ggplot(condition_frequency, aes(x = condition, y = log(frequency), fill = process.category)) +
geom_bar(stat = "identity", position = "stack") + # 'stack' stacks the bars for different conditions
labs(title = "Frequency of Diseases by Process Category",
x = "Condition",
y = "Frequency of Disease (log)",
fill = "Process Category") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotate x-axis labels for readability
print(logdisease_plot)

# Convert ggplot to interactive plotly chart
interactive_logdisease_plot <- ggplotly(logdisease_plot)
# Print the interactive plot
interactive_logdisease_plot
combined_no_dups <- combined_data %>%
filter(!is.na(Parent_Company)) %>% # Ensure process.category is not NA
distinct(id, diagnosis_date, .keep_all = TRUE) # Remove duplicates based on id and diagnosis_date
# Calculate frequencies
condition_frequency <- combined_no_dups %>%
group_by(Parent_Company, condition)%>%
filter(!is.na(Parent_Company)) %>%
summarize(frequency = n(), .groups = 'drop')
condition_frequency
# Plot the frequency of diseases by process category
disease_plot <-ggplot(condition_frequency, aes(x = condition, y = frequency, fill = Parent_Company)) +
geom_bar(stat = "identity", position = "stack") + # 'stack' stacks the bars for different conditions
labs(title = "Frequency of Diseases by parent company",
x = "Process Category",
y = "Frequency of Disease",
fill = "Condition") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotate x-axis labels for readability
# Convert ggplot to interactive plotly chart
interactive_disease_plot_parent <- ggplotly(disease_plot)
# Print the interactive plot
interactive_disease_plot_parent
#same but log
# Plot the frequency of diseases by process category
logdisease_parent_plot <-ggplot(condition_frequency, aes(x = condition, y = log(frequency), fill = Parent_Company)) +
geom_bar(stat = "identity", position = "stack") + # 'stack' stacks the bars for different conditions
labs(title = "Frequency of Diseases by parent company",
x = "Process Category (log)",
y = "Frequency of Disease",
fill = "Condition") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotate x-axis labels for readability
# Convert ggplot to interactive plotly chart
interactive_logdisease_plot_parent <- ggplotly(logdisease_parent_plot)
# Print the interactive plot
interactive_logdisease_plot_parent
# Define the data
dog_data <- data.frame(
Category = c("Died from Disease", "Survived or Died from Other Causes"),
Count = c(832, 3044 - 832)
)
# Create the pie chart
pie_chart <- plot_ly(dog_data, labels = ~Category, values = ~Count, type = 'pie',
textinfo = 'label+percent',
insidetextorientation = 'radial') %>%
layout(title = "Proportion of Dogs That Died from Disease")
# Print the pie chart
pie_chart
# Summarize data
death_summary <- Death_Data_Clean %>%
dplyr::count(is_cause_of_death) %>%
dplyr::mutate(Category = ifelse(is_cause_of_death == 1, "Died from Disease", "Did Not Die from Disease"))
# Rename columns for clarity
death_summary <- dplyr::rename(death_summary, Count = n)
# Create the pie chart
pie_chart_death_cause <- plot_ly(death_summary, labels = ~Category, values = ~Count, type = 'pie',
textinfo = 'label+percent',
insidetextorientation = 'radial') %>%
layout(title = "Proportion of Dogs Dying from Disease")
# Print the pie chart
pie_chart_death_cause
save(interactive_disease_plot,pie_chart,pie_chart_death_cause,interactive_disease_plot_parent,interactive_logdisease_plot,interactive_logdisease_plot_parent, file = "~/Dropbox (Edison_Lab@UGA)/Projects/vet/Deanna/Golden_Data/death2.RData")
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CiNwYWNrYWdlcwoKbGlicmFyeShkcGx5cikKbGlicmFyeShtYXJrb3ZjaGFpbikKCmBgYAoKIyMgTG9hZCBkYXRhCmBgYHtyfQojIFJlc3RvcmUgdGhlIG9iamVjdApEaWV0X0RhdGFfQ2xlYW4gPSByZWFkUkRTKGZpbGUgPSAifi9Ecm9wYm94IChFZGlzb25fTGFiQFVHQSkvUHJvamVjdHMvdmV0L0RlYW5uYS9Hb2xkZW5fRGF0YS9DbGVhbkRpZXREYXRhLnJkcyIpCkRlYXRoX0RhdGFfQ2xlYW4gPSByZWFkUkRTKGZpbGUgPSAifi9Ecm9wYm94IChFZGlzb25fTGFiQFVHQSkvUHJvamVjdHMvdmV0L0RlYW5uYS9Hb2xkZW5fRGF0YS9DbGVhbkRlYXRoRGF0YS5yZHMiKQpgYGAKCgojIyBGcmVxdWVuY3kgYXQgd2hpY2ggcGFydGljaXBhbnRzIHN3aXRjaCBjYXRlZ29yaXphdGlvbgpgYGB7cn0KCmRhdGEgPC0gRGlldF9EYXRhX0NsZWFuW29yZGVyKERpZXRfRGF0YV9DbGVhbiRpZCwgRGlldF9EYXRhX0NsZWFuJGNhbGVuZGFyeWVhciksXQoKICMgQ3JlYXRlIGEgbGlzdCBvZiBhbGwgdW5pcXVlIGNhdGVnb3JpZXMKYWxsX2NhdGVnb3JpZXMgPC0gdW5pcXVlKGRhdGEkcHJvY2Vzcy5jYXRlZ29yeSkKCiMgQ3JlYXRpbmcgc2VxdWVuY2VzCmRhdGFfc2VxdWVuY2UgPC0gZGF0YSAlPiUKICBncm91cF9ieShpZCkgJT4lCiAgc3VtbWFyaXNlKENhdGVnb3J5X1NlcXVlbmNlID0gbGlzdChwcm9jZXNzLmNhdGVnb3J5KSkgJT4lCiAgdW5ncm91cCgpCgoKIyBGdW5jdGlvbiB0byBmaXQgTWFya292IGNoYWluIGFuZCByZXR1cm4gYSBjb21wbGV0ZSB0cmFuc2l0aW9uIG1hdHJpeApnZXRfY29tcGxldGVfbWF0cml4IDwtIGZ1bmN0aW9uKHNlcXVlbmNlKSB7CiAgIyBGaXQgdGhlIE1hcmtvdiBjaGFpbgogIG1jRml0IDwtIG1hcmtvdmNoYWluRml0KGRhdGEgPSBzZXF1ZW5jZSkkZXN0aW1hdGUKICAjIENyZWF0ZSBhIGNvbXBsZXRlIG1hdHJpeCBpbmNsdWRpbmcgYWxsIGNhdGVnb3JpZXMKICBjb21wbGV0ZV9tYXRyaXggPC0gbWF0cml4KDAsIGxlbmd0aChhbGxfY2F0ZWdvcmllcyksIGxlbmd0aChhbGxfY2F0ZWdvcmllcyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1uYW1lcyA9IGxpc3QoYWxsX2NhdGVnb3JpZXMsIGFsbF9jYXRlZ29yaWVzKSkKICB0cmFuc2l0aW9ucyA8LSBtY0ZpdEB0cmFuc2l0aW9uTWF0cml4CiAgIyBGaWxsIHRoZSBjb21wbGV0ZSBtYXRyaXggd2l0aCBleGlzdGluZyB0cmFuc2l0aW9ucwogIHJvd25hbWVzX3RvX3VzZSA8LSBpbnRlcnNlY3Qocm93bmFtZXModHJhbnNpdGlvbnMpLCBhbGxfY2F0ZWdvcmllcykKICBjb2xuYW1lc190b191c2UgPC0gaW50ZXJzZWN0KGNvbG5hbWVzKHRyYW5zaXRpb25zKSwgYWxsX2NhdGVnb3JpZXMpCiAgY29tcGxldGVfbWF0cml4W3Jvd25hbWVzX3RvX3VzZSwgY29sbmFtZXNfdG9fdXNlXSA8LSB0cmFuc2l0aW9uc1tyb3duYW1lc190b191c2UsIGNvbG5hbWVzX3RvX3VzZV0KICByZXR1cm4oY29tcGxldGVfbWF0cml4KQp9CgojIEFkanVzdCB0aGUgZnVuY3Rpb24gdG8gY29udmVydCBzZXF1ZW5jZXMgdG8gdHJhbnNpdGlvbiBtYXRyaXgKZ2V0X3RyYW5zaXRpb25fbWF0cml4IDwtIGZ1bmN0aW9uKHNlcXVlbmNlX2xpc3QpIHsKICBtY0xpc3QgPC0gbGFwcGx5KHNlcXVlbmNlX2xpc3QsIGdldF9jb21wbGV0ZV9tYXRyaXgpCiAgCiAgIyBTdW1taW5nIGFsbCBtYXRyaWNlcwogIG1hdHJpeF9zdW0gPC0gUmVkdWNlKCIrIiwgbWNMaXN0KQogIHJldHVybihtYXRyaXhfc3VtIC8gbGVuZ3RoKG1jTGlzdCkpICAjIE5vcm1hbGl6aW5nCn0KCiMgQ3JlYXRpbmcgdGhlIHRyYW5zaXRpb24gbWF0cml4CnRyYW5zaXRpb25fbWF0cml4IDwtIGdldF90cmFuc2l0aW9uX21hdHJpeChkYXRhX3NlcXVlbmNlJENhdGVnb3J5X1NlcXVlbmNlKQpwcmludCh0cmFuc2l0aW9uX21hdHJpeCkKYGBgCgoKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCgp0cmFuc2l0aW9uX2RmIDwtIGFzLmRhdGEuZnJhbWUoYXMudGFibGUodHJhbnNpdGlvbl9tYXRyaXgpKQpjb2xuYW1lcyh0cmFuc2l0aW9uX2RmKSA8LSBjKCJGcm9tIiwgIlRvIiwgIkZyZXF1ZW5jeSIpCgpoZWF0bWFwMSA9IGdncGxvdCh0cmFuc2l0aW9uX2RmLCBhZXMoeCA9IEZyb20sIHkgPSBUbywgZmlsbCA9IEZyZXF1ZW5jeSkpICsKICBnZW9tX3RpbGUoKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIsIG1pZCA9ICJ3aGl0ZSIsIG1pZHBvaW50ID0gMC41KSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlRyYW5zaXRpb24gSGVhdG1hcCIsIHggPSAiRnJvbSBDYXRlZ29yeSIsIHkgPSAiVG8gQ2F0ZWdvcnkiLCBmaWxsID0gIlRyYW5zaXRpb24gRnJlcXVlbmN5IikKCmBgYAoKaW1wbGllcyBhIHNpZ25pZmljYW50IHRlbmRlbmN5IGZvciBzdWJqZWN0cyB0byByZW1haW4gaW4gdGhlIGxhc3QgY2F0ZWdvcnkgbGlzdGVkLiBUaGlzIGNhbiBpbmRpY2F0ZSB0aGF0IG9uY2Ugc3ViamVjdHMgZW50ZXIgdGhpcyBjYXRlZ29yeSwgdGhleSBhcmUgbGlrZWx5IHRvIHN0YXkgdGhlcmUsIHN1Z2dlc3Rpbmcgc3RhYmlsaXR5IG9yIGEgdGVybWluYWwgc3RhZ2UgZGVwZW5kaW5nIG9uIHRoZSBjb250ZXh0IG9mIHRoZSBzdHVkeS4KCgpgYGB7cn0KIyAKZGF0YSRZZWFyIDwtIGFzLmludGVnZXIoZGF0YSRjYWxlbmRhcnllYXIpCgojIENhbGN1bGF0ZSB0aGUgZHVyYXRpb24gb2Ygc3RheSBpbiBlYWNoIGNhdGVnb3J5IGZvciBlYWNoIHN1YmplY3QKZHVyYXRpb25zIDwtIGRhdGEgJT4lCiAgZ3JvdXBfYnkoaWQsIHByb2Nlc3MuY2F0ZWdvcnkpICU+JQogIHN1bW1hcmlzZSgKICAgIFN0YXJ0X1llYXIgPSBtaW4oWWVhciksCiAgICBFbmRfWWVhciA9IG1heChZZWFyKSwKICAgIER1cmF0aW9uID0gRW5kX1llYXIgLSBTdGFydF9ZZWFyICsgMSAgIyArMSBiZWNhdXNlIGlmIHN0YXJ0IGFuZCBlbmQgeWVhciBhcmUgdGhlIHNhbWUsIGR1cmF0aW9uIGlzIDEgeWVhcgogICkgJT4lCiAgdW5ncm91cCgpCgojIFZpZXcgdGhlIGZpcnN0IGZldyByb3dzIG9mIHRoZSBkdXJhdGlvbnMgZGF0YSBmcmFtZQpoZWFkKGR1cmF0aW9ucykKCiMgQ2FsY3VsYXRlIHRoZSBhdmVyYWdlIGR1cmF0aW9uIG9mIHN0YXkgcGVyIGNhdGVnb3J5CmF2ZXJhZ2VfZHVyYXRpb25zIDwtIGR1cmF0aW9ucyAlPiUKICBncm91cF9ieShwcm9jZXNzLmNhdGVnb3J5KSAlPiUKICBzdW1tYXJpc2UoQXZlcmFnZV9EdXJhdGlvbiA9IG1lYW4oRHVyYXRpb24pKQoKIyBWaWV3IHRoZSBhdmVyYWdlIGR1cmF0aW9ucwpoZWFkKGF2ZXJhZ2VfZHVyYXRpb25zKQoKCmR1cmF0aW9uc19kYXRhdGFibGUgPSBkYXRhdGFibGUoZHVyYXRpb25zLCBvcHRpb25zID0gbGlzdCgpLCBjbGFzcyA9ICJkaXNwbGF5IikKZHVyYXRpb25zX2RhdGF0YWJsZQoKYXZlcmFnZV9kdXJhdGlvbnNfZGF0YXRhYmxlID0gZGF0YXRhYmxlKGF2ZXJhZ2VfZHVyYXRpb25zLCBvcHRpb25zID0gbGlzdCgpLCBjbGFzcyA9ICJkaXNwbGF5IikKYXZlcmFnZV9kdXJhdGlvbnNfZGF0YXRhYmxlCmBgYApgYGB7cn0KIyBBZGRpbmcgYSBzbWFsbCBjb25zdGFudCB0byBoYW5kbGUgemVyb3MKayA9IDAuMDAxCnRyYW5zaXRpb25fZGYkRnJlcV9BZGp1c3RlZCA9IHRyYW5zaXRpb25fZGYkRnJlcSArIGsKIyBBcHBseWluZyBhIGxvZyB0cmFuc2Zvcm1hdGlvbiAoYmFzZSAxMCkKdHJhbnNpdGlvbl9kZiRMb2dfRnJlcXVlbmN5ID0gbG9nMTAodHJhbnNpdGlvbl9kZiRGcmVxX0FkanVzdGVkKQpgYGAKCmBgYHtyfQojIENvbnZlcnRpbmcgbWF0cml4IHRvIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCiN0cmFuc2l0aW9uX2RmIDwtIGFzLmRhdGEuZnJhbWUoYXMudGFibGUodHJhbnNpdGlvbl9tYXRyaXgpKQoKIyBDcmVhdGUgaW50ZXJhY3RpdmUgaGVhdG1hcApoZWF0bWFwMiA9IHBsb3RfbHkoZGF0YSA9IHRyYW5zaXRpb25fZGYsIHggPSB+RnJvbSwgeSA9IH5UbywgeiA9IH5Mb2dfRnJlcXVlbmN5LCB0eXBlID0gImhlYXRtYXAiLCBjb2xvcnMgPSBjb2xvclJhbXAoYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSksCiAgICAgICAgdGV4dCA9IH5wYXN0ZSgiVHJhbnNpdGlvbiBmcm9tIiwgRnJvbSwgInRvIiwgVG8sICI8YnI+UHJvYmFiaWxpdHk6IiwgRnJlcXVlbmN5KSwKICAgICAgICBob3ZlcmluZm8gPSAidGV4dCIpICU+JQogIGxheW91dCh0aXRsZSA9ICJUcmFuc2l0aW9uIE1hdHJpeCBIZWF0bWFwIiwKICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkZyb20gQ2F0ZWdvcnkiKSwKICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlRvIENhdGVnb3J5IiwgYXV0b3JhbmdlID0gInJldmVyc2VkIikpICAjIFJldmVyc2luZyB5LWF4aXMgdG8gbWF0Y2ggaGVhdG1hcCBjb252ZW50aW9ucwpoZWF0bWFwMgpgYGAKCiMjIEZyZXF1ZW5jeSBmb3Igc3dpdGNoaW5nIGRpZXQgY29tcGFuaWVzCgpgYGB7cn0KCiAjIENyZWF0ZSBhIGxpc3Qgb2YgYWxsIHVuaXF1ZSBjYXRlZ29yaWVzCmFsbF9jYXRlZ29yaWVzIDwtIHVuaXF1ZShkYXRhJFBhcmVudF9Db21wYW55KQoKIyBGdW5jdGlvbiB0byBmaXQgTWFya292IGNoYWluIGFuZCByZXR1cm4gYSBjb21wbGV0ZSB0cmFuc2l0aW9uIG1hdHJpeApnZXRfY29tcGxldGVfbWF0cml4IDwtIGZ1bmN0aW9uKHNlcXVlbmNlKSB7CiAgIyBGaXQgdGhlIE1hcmtvdiBjaGFpbgogIG1jRml0IDwtIG1hcmtvdmNoYWluRml0KGRhdGEgPSBzZXF1ZW5jZSkkZXN0aW1hdGUKICAjIENyZWF0ZSBhIGNvbXBsZXRlIG1hdHJpeCBpbmNsdWRpbmcgYWxsIGNhdGVnb3JpZXMKICBjb21wbGV0ZV9tYXRyaXggPC0gbWF0cml4KDAsIGxlbmd0aChhbGxfY2F0ZWdvcmllcyksIGxlbmd0aChhbGxfY2F0ZWdvcmllcyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1uYW1lcyA9IGxpc3QoYWxsX2NhdGVnb3JpZXMsIGFsbF9jYXRlZ29yaWVzKSkKICB0cmFuc2l0aW9ucyA8LSBtY0ZpdEB0cmFuc2l0aW9uTWF0cml4CiAgIyBGaWxsIHRoZSBjb21wbGV0ZSBtYXRyaXggd2l0aCBleGlzdGluZyB0cmFuc2l0aW9ucwogIHJvd25hbWVzX3RvX3VzZSA8LSBpbnRlcnNlY3Qocm93bmFtZXModHJhbnNpdGlvbnMpLCBhbGxfY2F0ZWdvcmllcykKICBjb2xuYW1lc190b191c2UgPC0gaW50ZXJzZWN0KGNvbG5hbWVzKHRyYW5zaXRpb25zKSwgYWxsX2NhdGVnb3JpZXMpCiAgY29tcGxldGVfbWF0cml4W3Jvd25hbWVzX3RvX3VzZSwgY29sbmFtZXNfdG9fdXNlXSA8LSB0cmFuc2l0aW9uc1tyb3duYW1lc190b191c2UsIGNvbG5hbWVzX3RvX3VzZV0KICByZXR1cm4oY29tcGxldGVfbWF0cml4KQp9CgojIEFkanVzdCB0aGUgZnVuY3Rpb24gdG8gY29udmVydCBzZXF1ZW5jZXMgdG8gdHJhbnNpdGlvbiBtYXRyaXgKZ2V0X3RyYW5zaXRpb25fbWF0cml4IDwtIGZ1bmN0aW9uKHNlcXVlbmNlX2xpc3QpIHsKICBtY0xpc3QgPC0gbGFwcGx5KHNlcXVlbmNlX2xpc3QsIGdldF9jb21wbGV0ZV9tYXRyaXgpCiAgCiAgIyBTdW1taW5nIGFsbCBtYXRyaWNlcwogIG1hdHJpeF9zdW0gPC0gUmVkdWNlKCIrIiwgbWNMaXN0KQogIHJldHVybihtYXRyaXhfc3VtIC8gbGVuZ3RoKG1jTGlzdCkpICAjIE5vcm1hbGl6aW5nCn0KCiMgQ3JlYXRpbmcgdGhlIHRyYW5zaXRpb24gbWF0cml4CnRyYW5zaXRpb25fbWF0cml4IDwtIGdldF90cmFuc2l0aW9uX21hdHJpeChkYXRhX3NlcXVlbmNlJENhdGVnb3J5X1NlcXVlbmNlKQoKYGBgCgoKYGBge3J9CiMgCmRhdGEkWWVhciA8LSBhcy5pbnRlZ2VyKGRhdGEkY2FsZW5kYXJ5ZWFyKQoKIyBDYWxjdWxhdGUgdGhlIGR1cmF0aW9uIG9mIHN0YXkgaW4gZWFjaCBjYXRlZ29yeSBmb3IgZWFjaCBzdWJqZWN0CmR1cmF0aW9ucyA8LSBkYXRhICU+JQogIGdyb3VwX2J5KGlkLCBQYXJlbnRfQ29tcGFueSkgJT4lCiAgc3VtbWFyaXNlKAogICAgU3RhcnRfWWVhciA9IG1pbihZZWFyKSwKICAgIEVuZF9ZZWFyID0gbWF4KFllYXIpLAogICAgRHVyYXRpb24gPSBFbmRfWWVhciAtIFN0YXJ0X1llYXIgKyAxICAjICsxIGJlY2F1c2UgaWYgc3RhcnQgYW5kIGVuZCB5ZWFyIGFyZSB0aGUgc2FtZSwgZHVyYXRpb24gaXMgMSB5ZWFyCiAgKSAlPiUKICB1bmdyb3VwKCkKCiMgVmlldyB0aGUgZmlyc3QgZmV3IHJvd3Mgb2YgdGhlIGR1cmF0aW9ucyBkYXRhIGZyYW1lCmhlYWQoZHVyYXRpb25zKQoKIyBDYWxjdWxhdGUgdGhlIGF2ZXJhZ2UgZHVyYXRpb24gb2Ygc3RheSBwZXIgY2F0ZWdvcnkKYXZlcmFnZV9kdXJhdGlvbnMgPC0gZHVyYXRpb25zICU+JQogIGdyb3VwX2J5KFBhcmVudF9Db21wYW55KSAlPiUKICBzdW1tYXJpc2UoQXZlcmFnZV9EdXJhdGlvbiA9IG1lYW4oRHVyYXRpb24pKQoKIyBWaWV3IHRoZSBhdmVyYWdlIGR1cmF0aW9ucwpoZWFkKGF2ZXJhZ2VfZHVyYXRpb25zKQoKCmR1cmF0aW9uc19kYXRhdGFibGUyID0gZGF0YXRhYmxlKGR1cmF0aW9ucywgb3B0aW9ucyA9IGxpc3QoKSwgY2xhc3MgPSAiZGlzcGxheSIpCmR1cmF0aW9uc19kYXRhdGFibGUKCmF2ZXJhZ2VfZHVyYXRpb25zX2RhdGF0YWJsZTIgPSBkYXRhdGFibGUoYXZlcmFnZV9kdXJhdGlvbnMsIG9wdGlvbnMgPSBsaXN0KCksIGNsYXNzID0gImRpc3BsYXkiKQphdmVyYWdlX2R1cmF0aW9uc19kYXRhdGFibGUKYGBgCiMjIEZyZXF1ZW5jeSBmb3Igc3dpdGNoaW5nIGRpZXQgYnJhbmRzCgpgYGB7cn0KCiAjIENyZWF0ZSBhIGxpc3Qgb2YgYWxsIHVuaXF1ZSBjYXRlZ29yaWVzCmFsbF9jYXRlZ29yaWVzIDwtIHVuaXF1ZShkYXRhJEJyYW5kX0NvbXBhbnkpCgojIEZ1bmN0aW9uIHRvIGZpdCBNYXJrb3YgY2hhaW4gYW5kIHJldHVybiBhIGNvbXBsZXRlIHRyYW5zaXRpb24gbWF0cml4CmdldF9jb21wbGV0ZV9tYXRyaXggPC0gZnVuY3Rpb24oc2VxdWVuY2UpIHsKICAjIEZpdCB0aGUgTWFya292IGNoYWluCiAgbWNGaXQgPC0gbWFya292Y2hhaW5GaXQoZGF0YSA9IHNlcXVlbmNlKSRlc3RpbWF0ZQogICMgQ3JlYXRlIGEgY29tcGxldGUgbWF0cml4IGluY2x1ZGluZyBhbGwgY2F0ZWdvcmllcwogIGNvbXBsZXRlX21hdHJpeCA8LSBtYXRyaXgoMCwgbGVuZ3RoKGFsbF9jYXRlZ29yaWVzKSwgbGVuZ3RoKGFsbF9jYXRlZ29yaWVzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbW5hbWVzID0gbGlzdChhbGxfY2F0ZWdvcmllcywgYWxsX2NhdGVnb3JpZXMpKQogIHRyYW5zaXRpb25zIDwtIG1jRml0QHRyYW5zaXRpb25NYXRyaXgKICAjIEZpbGwgdGhlIGNvbXBsZXRlIG1hdHJpeCB3aXRoIGV4aXN0aW5nIHRyYW5zaXRpb25zCiAgcm93bmFtZXNfdG9fdXNlIDwtIGludGVyc2VjdChyb3duYW1lcyh0cmFuc2l0aW9ucyksIGFsbF9jYXRlZ29yaWVzKQogIGNvbG5hbWVzX3RvX3VzZSA8LSBpbnRlcnNlY3QoY29sbmFtZXModHJhbnNpdGlvbnMpLCBhbGxfY2F0ZWdvcmllcykKICBjb21wbGV0ZV9tYXRyaXhbcm93bmFtZXNfdG9fdXNlLCBjb2xuYW1lc190b191c2VdIDwtIHRyYW5zaXRpb25zW3Jvd25hbWVzX3RvX3VzZSwgY29sbmFtZXNfdG9fdXNlXQogIHJldHVybihjb21wbGV0ZV9tYXRyaXgpCn0KCiMgQWRqdXN0IHRoZSBmdW5jdGlvbiB0byBjb252ZXJ0IHNlcXVlbmNlcyB0byB0cmFuc2l0aW9uIG1hdHJpeApnZXRfdHJhbnNpdGlvbl9tYXRyaXggPC0gZnVuY3Rpb24oc2VxdWVuY2VfbGlzdCkgewogIG1jTGlzdCA8LSBsYXBwbHkoc2VxdWVuY2VfbGlzdCwgZ2V0X2NvbXBsZXRlX21hdHJpeCkKICAKICAjIFN1bW1pbmcgYWxsIG1hdHJpY2VzCiAgbWF0cml4X3N1bSA8LSBSZWR1Y2UoIisiLCBtY0xpc3QpCiAgcmV0dXJuKG1hdHJpeF9zdW0gLyBsZW5ndGgobWNMaXN0KSkgICMgTm9ybWFsaXppbmcKfQoKIyBDcmVhdGluZyB0aGUgdHJhbnNpdGlvbiBtYXRyaXgKdHJhbnNpdGlvbl9tYXRyaXggPC0gZ2V0X3RyYW5zaXRpb25fbWF0cml4KGRhdGFfc2VxdWVuY2UkQ2F0ZWdvcnlfU2VxdWVuY2UpCgpgYGAKCgpgYGB7cn0KIyAKZGF0YSRZZWFyIDwtIGFzLmludGVnZXIoZGF0YSRjYWxlbmRhcnllYXIpCgojIENhbGN1bGF0ZSB0aGUgZHVyYXRpb24gb2Ygc3RheSBpbiBlYWNoIGNhdGVnb3J5IGZvciBlYWNoIHN1YmplY3QKZHVyYXRpb25zIDwtIGRhdGEgJT4lCiAgZ3JvdXBfYnkoaWQsIEJyYW5kX0NvbXBhbnkpICU+JQogIHN1bW1hcmlzZSgKICAgIFN0YXJ0X1llYXIgPSBtaW4oWWVhciksCiAgICBFbmRfWWVhciA9IG1heChZZWFyKSwKICAgIER1cmF0aW9uID0gRW5kX1llYXIgLSBTdGFydF9ZZWFyICsgMSAgIyArMSBiZWNhdXNlIGlmIHN0YXJ0IGFuZCBlbmQgeWVhciBhcmUgdGhlIHNhbWUsIGR1cmF0aW9uIGlzIDEgeWVhcgogICkgJT4lCiAgdW5ncm91cCgpCgojIFZpZXcgdGhlIGZpcnN0IGZldyByb3dzIG9mIHRoZSBkdXJhdGlvbnMgZGF0YSBmcmFtZQpoZWFkKGR1cmF0aW9ucykKCiMgQ2FsY3VsYXRlIHRoZSBhdmVyYWdlIGR1cmF0aW9uIG9mIHN0YXkgcGVyIGNhdGVnb3J5CmF2ZXJhZ2VfZHVyYXRpb25zIDwtIGR1cmF0aW9ucyAlPiUKICBncm91cF9ieShCcmFuZF9Db21wYW55KSAlPiUKICBzdW1tYXJpc2UoQXZlcmFnZV9EdXJhdGlvbiA9IG1lYW4oRHVyYXRpb24pKQoKIyBWaWV3IHRoZSBhdmVyYWdlIGR1cmF0aW9ucwpoZWFkKGF2ZXJhZ2VfZHVyYXRpb25zKQoKCmR1cmF0aW9uc19kYXRhdGFibGUzID0gZGF0YXRhYmxlKGR1cmF0aW9ucywgb3B0aW9ucyA9IGxpc3QoKSwgY2xhc3MgPSAiZGlzcGxheSIpCmR1cmF0aW9uc19kYXRhdGFibGUzCgphdmVyYWdlX2R1cmF0aW9uc19kYXRhdGFibGUzID0gZGF0YXRhYmxlKGF2ZXJhZ2VfZHVyYXRpb25zLCBvcHRpb25zID0gbGlzdCgpLCBjbGFzcyA9ICJkaXNwbGF5IikKYXZlcmFnZV9kdXJhdGlvbnNfZGF0YXRhYmxlMwpgYGAKCgpgYGB7cn0Kc2F2ZShoZWF0bWFwMiwgZmlsZSA9ICJ+L0Ryb3Bib3ggKEVkaXNvbl9MYWJAVUdBKS9Qcm9qZWN0cy92ZXQvRGVhbm5hL0dvbGRlbl9EYXRhL2ZpZ3VyZXNfdHJlbmRzLlJEYXRhIikKCnNhdmUoYXZlcmFnZV9kdXJhdGlvbnNfZGF0YXRhYmxlLGR1cmF0aW9uc19kYXRhdGFibGUsZHVyYXRpb25zX2RhdGF0YWJsZTIsYXZlcmFnZV9kdXJhdGlvbnNfZGF0YXRhYmxlMixhdmVyYWdlX2R1cmF0aW9uc19kYXRhdGFibGUzLGR1cmF0aW9uc19kYXRhdGFibGUzLCBmaWxlID0gIn4vRHJvcGJveCAoRWRpc29uX0xhYkBVR0EpL1Byb2plY3RzL3ZldC9EZWFubmEvR29sZGVuX0RhdGEvdGFibGVzX3RyZW5kcy5SRGF0YSIpCgoKYGBgCgojIERlYXRoIGRhdGEgYW5kIGRpZXQgZGF0YQoKYGBge3J9CiMgTWVyZ2UgdGhlIGRhdGFzZXRzCmNvbWJpbmVkX2RhdGEgPC0gbGVmdF9qb2luKERlYXRoX0RhdGFfQ2xlYW4sIERpZXRfRGF0YV9DbGVhbiwgYnkgPSBjKCJpZCIpKQoKYGBgCgoKYGBge3J9CiMgQ2FsY3VsYXRlIGZyZXF1ZW5jaWVzCmNvbmRpdGlvbl9mcmVxdWVuY3kgPC0gY29tYmluZWRfZGF0YSAlPiUKICBncm91cF9ieShwcm9jZXNzLmNhdGVnb3J5LCBjb25kaXRpb24pJT4lCiAgZmlsdGVyKCFpcy5uYShwcm9jZXNzLmNhdGVnb3J5KSkgJT4lCiAgc3VtbWFyaXplKGZyZXF1ZW5jeSA9IG4oKSwgLmdyb3VwcyA9ICdkcm9wJykKY29uZGl0aW9uX2ZyZXF1ZW5jeQoKIyBQbG90IHRoZSBmcmVxdWVuY3kgb2YgZGlzZWFzZXMgYnkgcHJvY2VzcyBjYXRlZ29yeQpkaXNlYXNlX3Bsb3QgPC1nZ3Bsb3QoY29uZGl0aW9uX2ZyZXF1ZW5jeSwgYWVzKHggPSBjb25kaXRpb24sIHkgPSBmcmVxdWVuY3ksIGZpbGwgPSBwcm9jZXNzLmNhdGVnb3J5KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsgICMgJ3N0YWNrJyBzdGFja3MgdGhlIGJhcnMgZm9yIGRpZmZlcmVudCBjb25kaXRpb25zCiAgbGFicyh0aXRsZSA9ICJGcmVxdWVuY3kgb2YgRGlzZWFzZXMgYnkgUHJvY2VzcyBDYXRlZ29yeSIsCiAgICAgICB4ID0gIlByb2Nlc3MgQ2F0ZWdvcnkiLAogICAgICAgeSA9ICJGcmVxdWVuY3kgb2YgRGlzZWFzZSIsCiAgICAgICBmaWxsID0gIkNvbmRpdGlvbiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIGZvciByZWFkYWJpbGl0eQpgYGAKCmBgYHtyfQojIHNhbWUgYnV0IHdpdGhvdXQgZHVwbGljYXRlcwoKY29tYmluZWRfbm9fZHVwcyA8LSBjb21iaW5lZF9kYXRhICU+JQogIGZpbHRlcighaXMubmEocHJvY2Vzcy5jYXRlZ29yeSkpICU+JSAgIyBFbnN1cmUgcHJvY2Vzcy5jYXRlZ29yeSBpcyBub3QgTkEKICBkaXN0aW5jdChpZCwgZGlhZ25vc2lzX2RhdGUsIC5rZWVwX2FsbCA9IFRSVUUpICAjIFJlbW92ZSBkdXBsaWNhdGVzIGJhc2VkIG9uIGlkIGFuZCBkaWFnbm9zaXNfZGF0ZQoKIyBDYWxjdWxhdGUgZnJlcXVlbmNpZXMKY29uZGl0aW9uX2ZyZXF1ZW5jeSA8LSBjb21iaW5lZF9ub19kdXBzICU+JQogIGdyb3VwX2J5KHByb2Nlc3MuY2F0ZWdvcnksIGNvbmRpdGlvbikgJT4lCiAgc3VtbWFyaXplKGZyZXF1ZW5jeSA9IG4oKSwgLmdyb3VwcyA9ICdkcm9wJykgICMgQ2FsY3VsYXRlIGZyZXF1ZW5jeSBhbmQgZHJvcCB0aGUgZ3JvdXBpbmcKCiMgUGxvdCB0aGUgZnJlcXVlbmN5IG9mIGRpc2Vhc2VzIGJ5IHByb2Nlc3MgY2F0ZWdvcnkKZGlzZWFzZV9wbG90IDwtIGdncGxvdChjb25kaXRpb25fZnJlcXVlbmN5LCBhZXMoeCA9IGNvbmRpdGlvbiwgeSA9IGZyZXF1ZW5jeSwgZmlsbCA9IHByb2Nlc3MuY2F0ZWdvcnkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIikgKyAgIyAnc3RhY2snIHN0YWNrcyB0aGUgYmFycyBmb3IgZGlmZmVyZW50IGNvbmRpdGlvbnMKICBsYWJzKHRpdGxlID0gIkZyZXF1ZW5jeSBvZiBEaXNlYXNlcyBieSBQcm9jZXNzIENhdGVnb3J5IiwKICAgICAgIHggPSAiQ29uZGl0aW9uIiwKICAgICAgIHkgPSAiRnJlcXVlbmN5IG9mIERpc2Vhc2UiLAogICAgICAgZmlsbCA9ICJQcm9jZXNzIENhdGVnb3J5IikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgZm9yIHJlYWRhYmlsaXR5CgpwcmludChkaXNlYXNlX3Bsb3QpCmBgYAoKCmBgYHtyfQojIENvbnZlcnQgZ2dwbG90IHRvIGludGVyYWN0aXZlIHBsb3RseSBjaGFydAppbnRlcmFjdGl2ZV9kaXNlYXNlX3Bsb3QgPC0gZ2dwbG90bHkoZGlzZWFzZV9wbG90KQoKIyBQcmludCB0aGUgaW50ZXJhY3RpdmUgcGxvdAppbnRlcmFjdGl2ZV9kaXNlYXNlX3Bsb3QKYGBgCgpgYGB7cn0KCgojIFBsb3QgdGhlIGZyZXF1ZW5jeSBvZiBkaXNlYXNlcyBieSBwcm9jZXNzIGNhdGVnb3J5IC0gbG9nCmxvZ2Rpc2Vhc2VfcGxvdCA8LSBnZ3Bsb3QoY29uZGl0aW9uX2ZyZXF1ZW5jeSwgYWVzKHggPSBjb25kaXRpb24sIHkgPSBsb2coZnJlcXVlbmN5KSwgZmlsbCA9IHByb2Nlc3MuY2F0ZWdvcnkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIikgKyAgIyAnc3RhY2snIHN0YWNrcyB0aGUgYmFycyBmb3IgZGlmZmVyZW50IGNvbmRpdGlvbnMKICBsYWJzKHRpdGxlID0gIkZyZXF1ZW5jeSBvZiBEaXNlYXNlcyBieSBQcm9jZXNzIENhdGVnb3J5IiwKICAgICAgIHggPSAiQ29uZGl0aW9uIiwKICAgICAgIHkgPSAiRnJlcXVlbmN5IG9mIERpc2Vhc2UgKGxvZykiLAogICAgICAgZmlsbCA9ICJQcm9jZXNzIENhdGVnb3J5IikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgZm9yIHJlYWRhYmlsaXR5CgpwcmludChsb2dkaXNlYXNlX3Bsb3QpCgojIENvbnZlcnQgZ2dwbG90IHRvIGludGVyYWN0aXZlIHBsb3RseSBjaGFydAppbnRlcmFjdGl2ZV9sb2dkaXNlYXNlX3Bsb3QgPC0gZ2dwbG90bHkobG9nZGlzZWFzZV9wbG90KQoKIyBQcmludCB0aGUgaW50ZXJhY3RpdmUgcGxvdAppbnRlcmFjdGl2ZV9sb2dkaXNlYXNlX3Bsb3QKYGBgCgoKYGBge3J9Cgpjb21iaW5lZF9ub19kdXBzIDwtIGNvbWJpbmVkX2RhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYShQYXJlbnRfQ29tcGFueSkpICU+JSAgIyBFbnN1cmUgcHJvY2Vzcy5jYXRlZ29yeSBpcyBub3QgTkEKICBkaXN0aW5jdChpZCwgZGlhZ25vc2lzX2RhdGUsIC5rZWVwX2FsbCA9IFRSVUUpICAjIFJlbW92ZSBkdXBsaWNhdGVzIGJhc2VkIG9uIGlkIGFuZCBkaWFnbm9zaXNfZGF0ZQoKCiMgQ2FsY3VsYXRlIGZyZXF1ZW5jaWVzCmNvbmRpdGlvbl9mcmVxdWVuY3kgPC0gY29tYmluZWRfbm9fZHVwcyAlPiUKICBncm91cF9ieShQYXJlbnRfQ29tcGFueSwgY29uZGl0aW9uKSU+JQogIGZpbHRlcighaXMubmEoUGFyZW50X0NvbXBhbnkpKSAlPiUKICBzdW1tYXJpemUoZnJlcXVlbmN5ID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKQpjb25kaXRpb25fZnJlcXVlbmN5CgojIFBsb3QgdGhlIGZyZXF1ZW5jeSBvZiBkaXNlYXNlcyBieSBwcm9jZXNzIGNhdGVnb3J5CmRpc2Vhc2VfcGxvdCA8LWdncGxvdChjb25kaXRpb25fZnJlcXVlbmN5LCBhZXMoeCA9IGNvbmRpdGlvbiwgeSA9IGZyZXF1ZW5jeSwgZmlsbCA9IFBhcmVudF9Db21wYW55KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsgICMgJ3N0YWNrJyBzdGFja3MgdGhlIGJhcnMgZm9yIGRpZmZlcmVudCBjb25kaXRpb25zCiAgbGFicyh0aXRsZSA9ICJGcmVxdWVuY3kgb2YgRGlzZWFzZXMgYnkgcGFyZW50IGNvbXBhbnkiLAogICAgICAgeCA9ICJQcm9jZXNzIENhdGVnb3J5IiwKICAgICAgIHkgPSAiRnJlcXVlbmN5IG9mIERpc2Vhc2UiLAogICAgICAgZmlsbCA9ICJDb25kaXRpb24iKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyBmb3IgcmVhZGFiaWxpdHkKYGBgCgpgYGB7cn0KIyBDb252ZXJ0IGdncGxvdCB0byBpbnRlcmFjdGl2ZSBwbG90bHkgY2hhcnQKaW50ZXJhY3RpdmVfZGlzZWFzZV9wbG90X3BhcmVudCA8LSBnZ3Bsb3RseShkaXNlYXNlX3Bsb3QpCgojIFByaW50IHRoZSBpbnRlcmFjdGl2ZSBwbG90CmludGVyYWN0aXZlX2Rpc2Vhc2VfcGxvdF9wYXJlbnQKYGBgCgpgYGB7cn0KI3NhbWUgYnV0IGxvZwoKIyBQbG90IHRoZSBmcmVxdWVuY3kgb2YgZGlzZWFzZXMgYnkgcHJvY2VzcyBjYXRlZ29yeQpsb2dkaXNlYXNlX3BhcmVudF9wbG90IDwtZ2dwbG90KGNvbmRpdGlvbl9mcmVxdWVuY3ksIGFlcyh4ID0gY29uZGl0aW9uLCB5ID0gbG9nKGZyZXF1ZW5jeSksIGZpbGwgPSBQYXJlbnRfQ29tcGFueSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siKSArICAjICdzdGFjaycgc3RhY2tzIHRoZSBiYXJzIGZvciBkaWZmZXJlbnQgY29uZGl0aW9ucwogIGxhYnModGl0bGUgPSAiRnJlcXVlbmN5IG9mIERpc2Vhc2VzIGJ5IHBhcmVudCBjb21wYW55IiwKICAgICAgIHggPSAiUHJvY2VzcyBDYXRlZ29yeSAobG9nKSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSBvZiBEaXNlYXNlIiwKICAgICAgIGZpbGwgPSAiQ29uZGl0aW9uIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgZm9yIHJlYWRhYmlsaXR5CgojIENvbnZlcnQgZ2dwbG90IHRvIGludGVyYWN0aXZlIHBsb3RseSBjaGFydAppbnRlcmFjdGl2ZV9sb2dkaXNlYXNlX3Bsb3RfcGFyZW50IDwtIGdncGxvdGx5KGxvZ2Rpc2Vhc2VfcGFyZW50X3Bsb3QpCgojIFByaW50IHRoZSBpbnRlcmFjdGl2ZSBwbG90CmludGVyYWN0aXZlX2xvZ2Rpc2Vhc2VfcGxvdF9wYXJlbnQKYGBgCgoKYGBge3J9CiMgRGVmaW5lIHRoZSBkYXRhCmRvZ19kYXRhIDwtIGRhdGEuZnJhbWUoCiAgQ2F0ZWdvcnkgPSBjKCJEaWVkIGZyb20gRGlzZWFzZSIsICJTdXJ2aXZlZCBvciBEaWVkIGZyb20gT3RoZXIgQ2F1c2VzIiksCiAgQ291bnQgPSBjKDgzMiwgMzA0NCAtIDgzMikKKQoKIyBDcmVhdGUgdGhlIHBpZSBjaGFydApwaWVfY2hhcnQgPC0gcGxvdF9seShkb2dfZGF0YSwgbGFiZWxzID0gfkNhdGVnb3J5LCB2YWx1ZXMgPSB+Q291bnQsIHR5cGUgPSAncGllJywKICAgICAgICAgICAgICAgICAgICAgdGV4dGluZm8gPSAnbGFiZWwrcGVyY2VudCcsCiAgICAgICAgICAgICAgICAgICAgIGluc2lkZXRleHRvcmllbnRhdGlvbiA9ICdyYWRpYWwnKSAlPiUKICBsYXlvdXQodGl0bGUgPSAiUHJvcG9ydGlvbiBvZiBEb2dzIFRoYXQgRGllZCBmcm9tIERpc2Vhc2UiKQoKIyBQcmludCB0aGUgcGllIGNoYXJ0CnBpZV9jaGFydApgYGAKCgpgYGB7cn0KIyBTdW1tYXJpemUgZGF0YQpkZWF0aF9zdW1tYXJ5IDwtIERlYXRoX0RhdGFfQ2xlYW4gJT4lCiAgZHBseXI6OmNvdW50KGlzX2NhdXNlX29mX2RlYXRoKSAlPiUKICBkcGx5cjo6bXV0YXRlKENhdGVnb3J5ID0gaWZlbHNlKGlzX2NhdXNlX29mX2RlYXRoID09IDEsICJEaWVkIGZyb20gRGlzZWFzZSIsICJEaWQgTm90IERpZSBmcm9tIERpc2Vhc2UiKSkKCiMgUmVuYW1lIGNvbHVtbnMgZm9yIGNsYXJpdHkKZGVhdGhfc3VtbWFyeSA8LSBkcGx5cjo6cmVuYW1lKGRlYXRoX3N1bW1hcnksIENvdW50ID0gbikKCiMgQ3JlYXRlIHRoZSBwaWUgY2hhcnQKcGllX2NoYXJ0X2RlYXRoX2NhdXNlIDwtIHBsb3RfbHkoZGVhdGhfc3VtbWFyeSwgbGFiZWxzID0gfkNhdGVnb3J5LCB2YWx1ZXMgPSB+Q291bnQsIHR5cGUgPSAncGllJywKICAgICAgICAgICAgICAgICAgICAgdGV4dGluZm8gPSAnbGFiZWwrcGVyY2VudCcsCiAgICAgICAgICAgICAgICAgICAgIGluc2lkZXRleHRvcmllbnRhdGlvbiA9ICdyYWRpYWwnKSAlPiUKICBsYXlvdXQodGl0bGUgPSAiUHJvcG9ydGlvbiBvZiBEb2dzIER5aW5nIGZyb20gRGlzZWFzZSIpCgojIFByaW50IHRoZSBwaWUgY2hhcnQKcGllX2NoYXJ0X2RlYXRoX2NhdXNlCmBgYAoKYGBge3J9CnNhdmUoaW50ZXJhY3RpdmVfZGlzZWFzZV9wbG90LHBpZV9jaGFydCxwaWVfY2hhcnRfZGVhdGhfY2F1c2UsaW50ZXJhY3RpdmVfZGlzZWFzZV9wbG90X3BhcmVudCxpbnRlcmFjdGl2ZV9sb2dkaXNlYXNlX3Bsb3QsaW50ZXJhY3RpdmVfbG9nZGlzZWFzZV9wbG90X3BhcmVudCwgZmlsZSA9ICJ+L0Ryb3Bib3ggKEVkaXNvbl9MYWJAVUdBKS9Qcm9qZWN0cy92ZXQvRGVhbm5hL0dvbGRlbl9EYXRhL2RlYXRoMi5SRGF0YSIpCmBgYAoK